﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JsEditor
{
    public class JsLexxer
    {

        Dictionary<String, String> wordToken = null;
        private String sourceString = null;

        private int sourceCursor = 0;
        private int sourceEnd = 0;
        private int lineEndChar = 0;
        private bool hitEOF = false;
        private int lineno = 0;
        private int EOF = 0;
        private static int
          EOF_CHAR = -1;

        private int getChar()
        {
            //if (ungetCursor != 0)
            //{
            //    return ungetBuffer[--ungetCursor];
            //}
            for (; ; )
            {
                int c = 0;
                if (sourceString != null)
                {
                    if (sourceCursor == sourceEnd)
                    {
                        hitEOF = true;
                        return EOF_CHAR;
                    }
                    c = sourceString.ToCharArray()[sourceCursor++];
                }
                if (c <= 127)
                {
                    if (c == '\n' || c == '\r')
                    {
                        lineEndChar = c;
                        c = '\n';
                    }
                }
                else
                {
                    //如果是Js的 回车
                }
                return c;
            }

        }

        public JsLexxer(String text, int line)
        {
            sourceString = text;
            lineno = line;
            sourceEnd = text.Length;
            BuildStaticToken();
        }

        public static bool isJSSpace(int c)
        {
            if (c <= 127)
            {
                return c == 0x20 || c == 0x9 || c == 0xC || c == 0xB;
            }
            else
            {
                return c == 0xA0;
            }
        }

        private bool dirtyLine = false;

        private char[] stringBuffer = new char[128];
        private int stringBufferTop;

        public String getStringFromBuffer()
        {
            return new string(stringBuffer, 0, stringBufferTop);
        }
        public void ClearBuffer()
        {
            stringBufferTop = 0;
        }

        private void addToString(int c)
        {
            int N = stringBufferTop;
            if (N == stringBuffer.Length)
            {
                char[] tmp = new char[stringBuffer.Length * 2];
                Array.Copy(stringBuffer, 0, tmp, 0, N);
                stringBuffer = tmp;
            }
            stringBuffer[N] = (char)c;
            stringBufferTop = N + 1;
        }

        //private bool matchChar(int test)
        //{
        //    int c = getCharIgnoreLineEnd();
        //    if (c == test)
        //    {
        //        return true;
        //    }
        //    else
        //    {
        //        ungetCharIgnoreLineEnd(c);
        //        return false;
        //    }
        //}
        private int end = 0;
        private int start = 0;
        public TokenLex nextToken()
        {
            int c = 0;
            while (true)
            {
                for (; ; )
                {
                    c = getChar();//取出一个字符
                    if (c == EOF_CHAR)//是否是结束符
                        return TokenLex.EOF;
                    else if (c == '\n')
                    {//如果是换行
                        dirtyLine = false;
                        return TokenLex.EOL;
                    }
                    else if (!isJSSpace(c))
                    {
                        if (c != '-')
                        {
                            dirtyLine = true;
                        }
                        break;
                    }

                }
                

                if (Character.isJavaIdentifierStart((char)c))
                {
                    this.start = sourceCursor;
                    //addToString(c);
                    while (Character.isJavaIdentifierStart((char)c))
                    {
                        addToString(c);
                        c = getChar();
                    }
                    String key = getStringFromBuffer();
                    ClearBuffer();
                    this.end = sourceCursor;
                    if (wordToken.ContainsKey(key))
                    {
                        return TokenLex.KeyWord;
                    }
                }


                #region 注释
                if (c == '/')
                {
                    this.start = sourceCursor;
                    //注释
                    c = getChar();
                    if (c == ('/'))
                    {
                        skipLine();
                        this.end = sourceCursor + 1;
                        return TokenLex.Comment;
                    }
                    if (c == ('*'))
                    {
                        bool lookForSlash = false;
                        for (; ; )
                        {
                            c = getChar();
                            if (c == EOF_CHAR)
                            {
                                //parser.addError("msg.unterminated.comment");
                                return TokenLex.Error;
                            }
                            else if (c == '*')
                            {
                                lookForSlash = true;
                            }
                            else if (c == '/')
                            {
                                if (lookForSlash)
                                {
                                    this.end = sourceCursor + 1;
                                    return TokenLex.CommentMult;
                                }
                            }
                            else
                            {
                                lookForSlash = false;
                            }
                        }
                    }
                }
                #endregion
                #region 字符
                if (c == '"' || c == '\'')
                {
                    this.start = sourceCursor;
                    int tmp = c;
                    //if (c == '\'')
                    //{
                    //bool isUnCode = false;
                    do
                    {

                        c = getChar();
                        if (c == '\\')
                        {

                            c = getChar();
                            if (c == 'n' | c == 't' | c == 'r' | c == '\'' | c == '\"')
                            {

                            }
                            else
                            {
                                return TokenLex.Error;
                            }
                        }

                    } while (c != tmp && (c != EOF_CHAR) && (c != '\n'));
                    if (c == '"' || c == '\'')
                    {
                        this.end = sourceCursor + 1;
                        return TokenLex.String;
                    }
                #endregion

                }

            }
        }// end for token





        private void skipLine()
        {
            // 跳出行
            int c;
            while ((c = getChar()) != EOF_CHAR && c != '\n') { }
            // ungetChar(c);
        }


        private void BuildStaticToken()
        {
            wordToken = new Dictionary<String, String>();

            wordToken.Add("break", "break");

            wordToken.Add("case", "case");
            wordToken.Add("catch", "catch");
            wordToken.Add("const", "const");
            wordToken.Add("continue", "continue");

            wordToken.Add("delete", "delete");
            wordToken.Add("debugger", "debugger");
            wordToken.Add("default", "default");
            wordToken.Add("do", "do");
            wordToken.Add("else", "else");
            wordToken.Add("finally", "finally");


            wordToken.Add("for", "for");
            wordToken.Add("function", "function");
            //流程语句
            wordToken.Add("if", "if");
            wordToken.Add("in", "in");
            wordToken.Add("instanceof", "instanceof");
            wordToken.Add("let", "let");
            wordToken.Add("new", "new");
            wordToken.Add("return", "return");
            wordToken.Add("switch", "switch");
            wordToken.Add("this", "this");
            wordToken.Add("throw", "throw");
            wordToken.Add("try", "try");
            wordToken.Add("typeof", "typeof");
            wordToken.Add("var", "var");
            wordToken.Add("void", "void");

            wordToken.Add("while", "while");

            wordToken.Add("with", "with");
            wordToken.Add("yield", "yield");
        }




        private int peekChar()
        {
            int c = getChar();
            // ungetChar(c);
            return c;
        }
        private static bool isDigit(int c)
        {
            return '0' <= c && c <= '9';
        }


        public int Start()
        {
            return start - 1;
        }
        public int End()
        {
            return end - 1;
        }


    }
    public enum TokenLex
    {
        EOF,
        EOL,
        Error,
        Comment,
        CommentMult,
        KeyWord,
        String,
        Number
    }

}